<html>
<head><meta charset="utf-8"><title>Inheritable TLS · t-libs · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/index.html">t-libs</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html">Inheritable TLS</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="238751063"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238751063" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eggyal <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238751063">(May 14 2021 at 11:23)</a>:</h4>
<p>Hello #t-libs!   I have a use-case that would greatly benefit from some form of "inheritable" thread-local storage; that is, storage that's initialized by the <em>spawning</em> thread (perhaps simply a clone of its own value), at the time the new thread is spawned similar to <a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/InheritableThreadLocal.html"><code>java.lang.InheritableThreadLocal</code></a> (<a href="https://patents.google.com/patent/US6820261B1/en">patent</a> expired 2019).</p>
<p>I believe that this must necessarily be implemented in spawning code, e.g. in <code>std::thread::Builder::spawn</code>, and indeed I have a working experiment.  I also understand that such a change will require an RFC, especially to settle the user-facing interface—and so I'm seeking feedback before I begin writing one (which will be my first).</p>
<p>FWIW, my current experiment (to which I'm in no way wedded) stores a slice of keys in a global static (which I currently initialize, via an exposed intiailization function, upon application startup: it would be great to instead find some way to do this via an attribute on the key declaration, but I guess that would require new language features?).  Then, whenever a thread is spawned, the elements of that slice are inherited in two stages: first in the spawning thread (which calls a method on <code>InheritableLocalKey</code> to obtain a <code>FnOnce</code> closure); and then in the spawned thread (which invokes the closure to initialize the TLS):</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">static</span><span class="w"> </span><span class="n">INHERITABLE_TLS_KEYS</span>: <span class="nc">SyncOnceCell</span><span class="o">&lt;&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="p">[</span><span class="o">&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="k">dyn</span><span class="w"> </span><span class="n">InheritableLocalKey</span><span class="p">]</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">SyncOnceCell</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">set_inheritable_tls</span><span class="p">(</span><span class="n">keys</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="nb">static</span> <span class="p">[</span><span class="o">&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="k">dyn</span><span class="w"> </span><span class="n">InheritableLocalKey</span><span class="p">])</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">INHERITABLE_TLS_KEYS</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">keys</span><span class="p">).</span><span class="n">ok</span><span class="p">().</span><span class="n">expect</span><span class="p">(</span><span class="s">"inheritable tls keys already set"</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">trait</span><span class="w"> </span><span class="n">InheritableLocalKey</span>: <span class="nb">Sync</span> <span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="c1">// called in spawning thread to obtain a closure</span>
<span class="w">    </span><span class="c1">// that will be called in the spawned thread to initialize the TLS</span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">inherit</span><span class="p">(</span><span class="o">&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span><span class="w"> </span><span class="nb">FnOnce</span><span class="p">()</span><span class="o">&gt;</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">trait</span><span class="w"> </span><span class="n">Initialize</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="c1">// called in spawned thread to set the TLS</span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w">  </span><span class="n">val</span>: <span class="nc">Self</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// implementations of Initiailize provided for common TLS types e.g.</span>
<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Initialize</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">OnceCell</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">val</span>: <span class="nc">Self</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">val</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">val</span><span class="p">.</span><span class="n">into_inner</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">val</span><span class="p">).</span><span class="n">ok</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Initialize</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">RefCell</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">val</span>: <span class="nc">Self</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">replace</span><span class="p">(</span><span class="n">val</span><span class="p">.</span><span class="n">into_inner</span><span class="p">());</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// I use this blanket "Clone" implementation</span>
<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">Initialize</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Clone</span><span class="o">&gt;</span><span class="w"> </span><span class="n">InheritableLocalKey</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">LocalKey</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">interit</span><span class="p">(</span><span class="o">&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span><span class="w"> </span><span class="nb">FnOnce</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">with</span><span class="p">(</span><span class="nb">Clone</span>::<span class="n">clone</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">with</span><span class="p">(</span><span class="o">|</span><span class="n">content</span><span class="o">|</span><span class="w"> </span><span class="n">content</span><span class="p">.</span><span class="n">initialize</span><span class="p">(</span><span class="n">clone</span><span class="p">)))</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>What are your thoughts?  Would this be welcome in std?  If so, should I post a pre-RFC on IRLO, or just submit an RFC directly?  Is there anyone who would be willing to steward this?</p>



<a name="238794604"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238794604" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Josh Triplett <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238794604">(May 14 2021 at 16:40)</a>:</h4>
<p>Would it suffice if a thread builder allowed you to specify one or more separate closures that ran <em>before</em> the thread's closure, in the context of the thread?</p>



<a name="238794719"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238794719" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Josh Triplett <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238794719">(May 14 2021 at 16:41)</a>:</h4>
<p>For instance, <code>thread::Builder::new().setup(|| do initialization here).spawn(|| the actual thread closure)</code>?</p>



<a name="238796036"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238796036" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eggyal <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238796036">(May 14 2021 at 16:51)</a>:</h4>
<p>Hi Josh, I'm afraid not... my particular use case is an instrumented test-runner, which uses <code>-Zinstrument-coverage</code> to inject instrumentation calls into the crate under test and then runs that crate's tests in different threads within a single process; I need each instrumentation event to be associated with the relevant test, but those tests may themselves spawn further threads—and I have no control over that code.  With inheritable TLS, I can set the value on each test's main thread before it's launched and then any further threads launched by that test will inherit the value.</p>



<a name="238804371"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238804371" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Josh Triplett <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238804371">(May 14 2021 at 17:50)</a>:</h4>
<p>Ah, I see.</p>



<a name="238881857"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238881857" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> The 8472 <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238881857">(May 15 2021 at 08:54)</a>:</h4>
<p>That wouldn't work if they use any way other than std's thread building though. Or with threadpools for that matter.</p>



<a name="238883299"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238883299" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eggyal <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238883299">(May 15 2021 at 09:20)</a>:</h4>
<p><span class="user-mention silent" data-user-id="330154">The 8472</span> <a href="#narrow/stream/219381-t-libs/topic/Inheritable.20TLS/near/238881857">said</a>:</p>
<blockquote>
<p>That wouldn't work if they use any way other than std's thread building though.</p>
</blockquote>
<p>Aye, I had considered that and figured, for now, it'd just have to be documented as a known limitation.  How common are other ways of building threads, I wonder?  In my case, there's an escape hatch through which tests can be configured to run in their own process or at worst serially.</p>
<blockquote>
<p>Or with threadpools for that matter.</p>
</blockquote>
<p>This is no different to existing TLS, so I don't think that's an issue in the general case?  For my particular case, if a test launches a thread pool then all workers would belong to that test so I don't think this is an issue for me?  (My test-runner does not use a thread pool for the tests themselves).</p>



<a name="238913198"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238913198" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> The 8472 <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238913198">(May 15 2021 at 17:30)</a>:</h4>
<p>A thread pool may be stored to a static of a crate. So if multiple tests share a dependency that manages a thread-pool in static vars then the first test touching the pool would initialize the inheritable TLS there.</p>
<p>And thread pools + TLS being a problem... depends on how they are used. If you use it as a sort of implicit down-stack parameter passing thing and clean it up at the end then it can work on a thread pool. Things automatically getting cloned into other thread makes cleanup more difficult.</p>
<blockquote>
<p>How common are other ways of building threads, I wonder?</p>
</blockquote>
<p>Depends a lot on how much FFI is being used. Rust definitely supports code getting called from threads not created by std.</p>



<a name="238916069"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238916069" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eggyal <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238916069">(May 15 2021 at 18:21)</a>:</h4>
<p><del>I think it must be very rare for tests that share globally mutable state, whether a thread pool or anything else, to successfully run on a multithreaded test-runner?</del>  This is where clear documentation together with the escape hatch of dispatching isolate processes, or serial execution, will be necessary.  And whilst my use-case is perhaps a little niche, I suspect there must occasionally be other situations where inheritable TLS could also be useful (I haven't explored the motivations for inheritable TLS in Java, but they could well apply in Rust too)?</p>



<a name="238916598"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238916598" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eggyal <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238916598">(May 15 2021 at 18:28)</a>:</h4>
<p>Hm.  On reflection, maybe my first comment there is nonsense.</p>



<a name="238916780"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238916780" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> The 8472 <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238916780">(May 15 2021 at 18:31)</a>:</h4>
<p>I guess java's model has something to do with webservers frameworks where a request has some context attached and the context is passed via TLS and that can be passed to threads spawned by the request.<br>
Something like this: <a href="https://docs.spring.io/spring-framework/docs/5.0.2.RELEASE/javadoc-api/org/springframework/web/filter/RequestContextFilter.html#setThreadContextInheritable-boolean-">https://docs.spring.io/spring-framework/docs/5.0.2.RELEASE/javadoc-api/org/springframework/web/filter/RequestContextFilter.html#setThreadContextInheritable-boolean-</a><br>
Complete with warning.</p>



<a name="238916966"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238916966" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eggyal <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238916966">(May 15 2021 at 18:33)</a>:</h4>
<p>So I guess the question is, is valid usage sufficiently clear and useful to justify such a feature in std?</p>



<a name="238918159"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238918159" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> The 8472 <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238918159">(May 15 2021 at 18:55)</a>:</h4>
<p>It's not so much a matter of valid usage being clear but whether people can even control it. It might not compose well with things done by 3rd party crates. Async, FFI, thread pools.<br>
E.g. tokio has its own <code>task_local!</code> because thread locals just don't work for them.</p>



<a name="238918303"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238918303" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> The 8472 <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238918303">(May 15 2021 at 18:58)</a>:</h4>
<p>Maybe std's thread builder could be made hookable then inheritable TLS could be implemented in a crate.</p>



<a name="238919096"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Inheritable%20TLS/near/238919096" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eggyal <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Inheritable.20TLS.html#238919096">(May 15 2021 at 19:11)</a>:</h4>
<p>All good points.  I'll give this some more thought.  Thanks so much for your input!</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>